package org.pp.service.impl;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.pp.admin.dto.InfoUpdate;
import org.pp.admin.dto.Login;
import org.pp.admin.dto.PasswordUpdate;
import org.pp.core.AdminConstants;
import org.pp.core.AdminSessionUtil;
import org.pp.core.Assertion;
import org.pp.core.BizExcept;
import org.pp.entity.SysRoleMenu;
import org.pp.entity.SysUser;
import org.pp.entity.SysUserRole;
import org.pp.service.*;
import org.pp.util.JwtUtil;
import org.pp.util.RedisUtil;
import org.pp.vo.AdminLoginCodeVo;
import org.pp.vo.AdminLoginVo;
import org.pp.vo.AdminUserInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SysLoginServiceImpl implements ISysLoginService {
    @Autowired
    RedisUtil redisUtil;

    @Autowired
    ISysUserService userService;

    @Autowired
    ISysUserRoleService userRoleService;

    @Autowired
    ISysRoleMenuService roleMenuService;

    @Autowired
    ISysMenuService menuService;



    private SysUser exist(Long userId) {
        SysUser user = userService.getById(userId);
        if (Objects.isNull(user)) {
            throw BizExcept.erro("用户不存在");
        }
        return user;
    }

    @Override
    public AdminLoginCodeVo getCode() {
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(80, 35, 4, 20);
        RandomGenerator randomGenerator = new RandomGenerator("0123456789ABCDEFGHIJK", 4);
        lineCaptcha.setGenerator(randomGenerator);
        String code = lineCaptcha.getCode();
        log.info("验证码是:{}", code);
        String codeImage = StrUtil.format("data:image/png;base64,{}", lineCaptcha.getImageBase64());
        AdminLoginCodeVo vo = new AdminLoginCodeVo();
        String key = IdUtil.fastUUID();
        vo.setKey(key);
        vo.setCode(codeImage);
        redisUtil.set(key, code, 5L, TimeUnit.MINUTES);
        return vo;
    }

    @Override
    public AdminLoginVo login(Login dto) {
        //校验验证码
        String code = redisUtil.get(dto.getKey());
        if (StrUtil.isBlank(code) || !code.equalsIgnoreCase(dto.getCode())) {
            throw BizExcept.erro("验证码错误");
        }

        //校验密码
        SysUser user = userService.getOne(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUserName, dto.getUserName()));
        if (Objects.isNull(user) || !AdminSessionUtil.checkPassword(dto.getPassword(), user.getPassword())) {
            throw BizExcept.erro("用户名或密码错误");
        }
        Assertion.equalsThrow(AdminConstants.statusDisabled,user.getStatus(),"用户状态异常");

        //生成并放到redis
        String jwtToken = JwtUtil.createJwtToken(Map.of(AdminConstants.jwtLoginKey, user.getUserId()),
                AdminConstants.jwtExpireUnit, AdminConstants.jwtExpireTime);

        redisUtil.set(AdminSessionUtil.getLoginUserNameKey(user.getUserId()),
                user.getUserName(), AdminConstants.jwtExpireTime, AdminConstants.jwtExpireUnit);

        redisUtil.delete(dto.getKey());
        AdminLoginVo adminLoginVo = BeanUtil.copyProperties(user, AdminLoginVo.class);
        adminLoginVo.setToken(jwtToken);
        List<Long> roleIds = userRoleService.list(new LambdaQueryWrapper<SysUserRole>()
                .eq(SysUserRole::getUserId, user.getUserId())).stream().map(SysUserRole::getRoleId).toList();

        redisUtil.delete(AdminConstants.loginUserRoles+":"+user.getUserId());
        redisUtil.add(AdminConstants.loginUserRoles+":"+user.getUserId(),roleIds);
        return adminLoginVo;
    }

    @Override
    public void logout() {
        Long userId = AdminSessionUtil.getUserId();
        redisUtil.delete(AdminSessionUtil.getLoginUserNameKey(userId));
    }

    @Override
    public void passwordUpdate(PasswordUpdate dto) {
        Long userId = AdminSessionUtil.getUserId();
        SysUser user = exist(userId);
        if (!AdminSessionUtil.checkPassword(dto.getPassword(), user.getPassword())) {
            throw BizExcept.erro("旧密码错误");
        }
        SysUser editeUser = new SysUser();
        editeUser.setUserId(userId);
        editeUser.setPassword(AdminSessionUtil.encrypt(dto.getNewPassword()));
        userService.updateById(editeUser);
        redisUtil.delete(AdminSessionUtil.getLoginUserNameKey(userId));
    }


    @Override
    public void infoUpdate(InfoUpdate dto) {
        Long userId = AdminSessionUtil.getUserId();
        SysUser user = exist(userId);
        SysUser editeUser = new SysUser();
        editeUser.setPhone(dto.getPhone());
        editeUser.setName(dto.getName());
        editeUser.setUserId(userId);
        userService.updateById(editeUser);
    }

    @Override
    public AdminUserInfoVo userInfo() {
        SysUser user = exist(AdminSessionUtil.getUserId());
        AdminUserInfoVo vo = BeanUtil.copyProperties(user, AdminUserInfoVo.class);
        List<SysUserRole> roles = userRoleService.list(new LambdaQueryWrapper<SysUserRole>()
                .eq(SysUserRole::getUserId, user.getUserId()));
        List<Long> roleIds = roles.stream().map(SysUserRole::getRoleId).toList();

        //不校验权限的角色，返回所有权限
        if(Objects.nonNull(AdminConstants.permissionNocheckRole)&&
                !CollectionUtil.isEmpty(roleIds)&&roleIds.contains(AdminConstants.permissionNocheckRole)){
            vo.setAuths(menuService.tree());
            vo.setRoleIds(roleIds);
            return vo;
        }
        List<SysRoleMenu> menus = CollectionUtil.isEmpty(roleIds)?new ArrayList<>(): roleMenuService.list(new LambdaQueryWrapper<SysRoleMenu>()
                .in(SysRoleMenu::getRoleId, roleIds));

        vo.setRoleIds(roleIds);
        Set<Long> menuIds = menus.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toSet());
        vo.setAuths(CollectionUtil.isEmpty(menuIds)?new ArrayList<>():  menuService.tree(menuIds));
        return vo;
    }


   /* public static void main(String[] args) {
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(80, 35, 4, 20);
        RandomGenerator randomGenerator = new RandomGenerator("0123456789ABCDEFGHIJK", 4);
        lineCaptcha.setGenerator(randomGenerator);
        System.out.println(lineCaptcha.getCode());
        System.out.println(StrUtil.format("data:image/png;base64,{}", lineCaptcha.getImageBase64()));
    }*/
}
